package edu.cmu.cs.lti.ark.dageem;

public abstract class AgendaAlgorithm {

	protected Agenda agenda;
	protected Chart chart;
	protected boolean useSecondary;

	public AgendaAlgorithm(boolean useSecondary) {
		agenda = new Agenda(useSecondary);
		this.useSecondary = useSecondary;
	}

	public void setChart(Chart c) {
		agenda.setChart(c);
		chart = c;
	}

	public Chart getChart() {
		return chart;
	}

	public void clear(boolean useSecondary) {
		agenda = new Agenda(useSecondary);
		agenda.setChart(chart);
	}

	public abstract void processedPoppedTerm(Term poppedTerm, int poppedHash,
			double poppedValue, EValue poppedSecondary);

	public void assertTerm(Term t) {
		agenda.markAgendaItem(t, t.value(), t.secondaryValue(), null, true);
	}

	public abstract boolean isGoal(Term t);

	public boolean agendaIterator() {
		double poppedValue;
		Term poppedTerm;
		EValue poppedSecondaryValue;
		BacktrackChain poppedBacktrack = null;

		Agenda.PoppedValueContainer container = new Agenda.PoppedValueContainer();
		boolean popped = agenda.pop(container);
		poppedTerm = container.myTerm;
		poppedBacktrack = container.myBacktrack;
		poppedValue = container.myValue;
		poppedSecondaryValue = (EValue) container.myObject;

		if (!popped) {
			return false;
		}

		int poppedHash = poppedTerm.hashcode();

		double oldValue = chart.currVal(poppedHash);

		// in the paper:
		// delta -> poppedValue
		// old -> oldValue

		boolean changed = false;

		double v = Chart.Semiring.Plus(oldValue, poppedValue);
		poppedTerm.setValue(v);

		if (!chart.hasTerm(poppedHash)) {
			chart.addTerm(poppedTerm);
		}

		if (useSecondary) {
			if (poppedTerm.secondaryValue() == null) {
				poppedTerm.setSecondaryValue(poppedSecondaryValue);
				changed = true;
			} else {
				changed = ((EValue) (poppedTerm.secondaryValue()))
						.Plus(poppedSecondaryValue);
			}
		}

		if (oldValue != v) {
			changed = true;
		}
		
		if (!changed) { return true; }
		//changed = true;
		
		// notice this trick is for the max semiring
		if (changed) {
			// set val
			// poppedTerm.setValue(poppedValue);

			if (useSecondary) {
				// poppedTerm.secondaryValue().Plus(poppedSecondaryValue);
			}

			if ((oldValue <= v) && (Chart.Semiring.Idempotent())) {
				chart.addBacktrack(poppedHash, poppedBacktrack, poppedValue);
			}

			processedPoppedTerm(poppedTerm, poppedHash, poppedValue,
					(EValue) poppedSecondaryValue);
		}

		if ((!useSecondary) && (Chart.Semiring.Idempotent())
				&& (isGoal(poppedTerm))) {
			return false;
		}

		return true;
	}
}